﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Silverlight4Demo.Utility.CustomControl {

    /// <summary>
    /// these attributes is required in order for control to be modified by tool (Blend 4). They are used only by tools not by the runtime.
    /// </summary>
    [TemplatePart(Name = "Core", Type = typeof(FrameworkElement))]
    [TemplateVisualState(Name = "Normal", GroupName = "NormalStates")]
    [TemplateVisualState(Name = "MouseOver", GroupName = " NormalStates")]
    [TemplateVisualState(Name = "Pressed", GroupName = " NormalStates")]
    [TemplateVisualState(Name = "CoolDown", GroupName = "CoolDownStates")]
    [TemplateVisualState(Name = "Available", GroupName = "CoolDownStates")]
    public class CoolDownButton : Control {

        private FrameworkElement corePart; //hold the instance of the main part and respond the mouse events.
        // In this case, custom control consists of a lot of parts, but only core part can be respond the OS events (as mouse events)
        private bool isPressed, isMouseOver, isCoolDown;
        private DateTime pressedTime;


        public CoolDownButton( ) {
            //define the default style key, style file or setting can bind to this control by the key.
            DefaultStyleKey = typeof(CoolDownButton);
        }

        public static readonly DependencyProperty CoolDownSecondsProperty =
            DependencyProperty.Register(
                    "CoolDownSeconds",
                    typeof(int),
                    typeof(CoolDownButton),
                    new PropertyMetadata(
                        CoolDownButton.OnCoolDownSecondsPropertyChanged
                        )
            );

        public int CoolDownSeconds {
            get {
                return (int)GetValue(CoolDownSecondsProperty);
            }
            set {
                SetValue(CoolDownSecondsProperty, value);
            }
        }

        private static void OnCoolDownSecondsPropertyChanged(
           DependencyObject d, DependencyPropertyChangedEventArgs e) {
            CoolDownButton cdButton = d as CoolDownButton;

            cdButton.OnCoolDownButtonChange(null);
        }

        public static readonly DependencyProperty ButtonTextProperty =
            DependencyProperty.Register(
                "ButtonText",
                typeof(string),
                typeof(CoolDownButton),
                new PropertyMetadata(
                    new PropertyChangedCallback(
                        CoolDownButton.OnButtonTextPropertyChanged
                        )
                    )
                );
        public string ButtonText {
            get {
                return (string)GetValue(ButtonTextProperty);
            }
            set {
                SetValue(ButtonTextProperty, value);
            }
        }

        private static void OnButtonTextPropertyChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e) {
                CoolDownButton cdButton = d as CoolDownButton;
            cdButton.OnCoolDownButtonChange(null);
        }

        /// <summary>
        /// when the main properties is changed, it will call this method to change the state and the appearance of the control immediately
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnCoolDownButtonChange(RoutedEventArgs e) {
            GoToState(true);
        }

        //control the visual state of the custom control by the state.
        private void GoToState(bool useTransitions) {
            if (isPressed) {
                VisualStateManager.GoToState(this, "Pressed", useTransitions);
            } else if (isMouseOver) {
                VisualStateManager.GoToState(this, "MouseOver", useTransitions);
            } else {
                VisualStateManager.GoToState(this, "Normal", useTransitions);
            }

            if (isCoolDown) {
                VisualStateManager.GoToState(this, "CoolDown", useTransitions);
            } else {
                VisualStateManager.GoToState(this, "Available", useTransitions);
            }
        }

        public override void OnApplyTemplate( ) {
            base.OnApplyTemplate( );
            CorePart = (FrameworkElement)GetTemplateChild("corePart");//get the rectangle named 'corePart', let it be the core part to respond the mouse event
            GoToState(false);//first be called
        }

        private FrameworkElement CorePart {
            get { return corePart; }
            set {
                //when corePart is set, remove the events binding of the old core part , and then bind event to the new one
                var oldCorePart = corePart;
                if (oldCorePart != null) {
                    oldCorePart.MouseEnter -= corePart_MouseEnter;
                    oldCorePart.MouseLeave -= corePart_MouseLeave;
                    oldCorePart.MouseLeftButtonDown -= corePart_MouseLeftButtonDown;
                    oldCorePart.MouseLeftButtonUp -= corePart_MouseLeftButtonUp;
                }
                corePart = value;
                if (corePart != null) {
                    corePart.MouseEnter += corePart_MouseEnter;
                    corePart.MouseLeave += corePart_MouseLeave;
                    corePart.MouseLeftButtonDown += corePart_MouseLeftButtonDown;
                    corePart.MouseLeftButtonUp += corePart_MouseLeftButtonUp;
                }

            }
        }

        private bool CheckCoolDown( ) {
            if (!isCoolDown) {
                return false;
            } else {
                if (DateTime.Now > pressedTime.AddSeconds(CoolDownSeconds)) {
                    isCoolDown = false;
                    return false;
                } else {
                    return true;
                }
            }
        }

        void corePart_MouseEnter(object sender, MouseEventArgs e) {
            if (!CheckCoolDown( )) {
                isMouseOver = true;
                GoToState(true);
            }
        }

        void corePart_MouseLeave(object sender, MouseEventArgs e) {
            if (!CheckCoolDown( )) {
                isMouseOver = false;
                GoToState(true);
            }
        }

        void corePart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
            if (!CheckCoolDown( )) {
                isPressed = true;
                GoToState(true);
            }
        }

        void corePart_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
            if (!CheckCoolDown( )) {
                isPressed = false;
                isCoolDown = true;
                pressedTime = DateTime.Now;
                GoToState(true);
            }
        }
    }
}
